package config

import (
	"fmt"
	"time"

	"github.com/redis/go-redis/v9"
	"github.com/spf13/viper"
)

type Database struct {
	Host               string `mapstructure:"host"`
	Port               string `mapstructure:"port"`
	Username           string `mapstructure:"username"`
	Password           string `mapstructure:"password"`
	Database           string `mapstructure:"database"`
	MaxIdleConnections int    `mapstructure:"maxIdleConns"`
	MaxOpenConnections int    `mapstructure:"maxOpenConns"`
}
type SnmpTaskConfig struct {
	BatchSize     int
	MaxGoroutines int
}

var (
	DbConfig     *Database //设置全局的引用型指针变量
	Rediscfg     *RedisConfig
	LogCfg       *LogConfig = &LogConfig{BasePath: "./logs", MaxSize: 100, MaxAge: 7, MaxBackup: 3, Compress: true}
	SnmpTaskCfg  *SnmpTaskConfig
	HeartBeatCfg *HeartBeatConfig
	PidsConfig   *PidsConfiguration // 新增 PidsToken 配置
)

func init() {
	// 自动读取环境变量
	viper.AutomaticEnv()
	// 绑定环境变量到配置项，优先使用环境变量
	viper.BindEnv("datasource.host", "DB_HOST") // 如果设置了DB_HOST环境变量，优先使用它
	viper.BindEnv("datasource.port", "DB_PORT")
	viper.BindEnv("datasource.username", "DB_USER")
	viper.BindEnv("datasource.password", "DB_PASSWORD")
	viper.BindEnv("datasource.database", "DB_NAME")
	viper.BindEnv("datasource.maxIdleConns", "DB_IDLECOUNT")
	viper.BindEnv("datasource.maxOpenConns", "DB_OPENCOUNT")

	viper.BindEnv("redis.mode", "REDIS_MODE")        // Redis模式
	viper.BindEnv("redis.single.host", "REDIS_HOST") // Redis主机
	viper.BindEnv("redis.single.port", "REDIS_PORT") // Redis端口
	viper.BindEnv("redis.single.password", "REDIS_PASSWORD")
	viper.BindEnv("redis.single.db", "REDIS_DB")

	viper.BindEnv("redis.cluster.addrs", "REDIS_CLUSTER_HOST")        //redis集群地址
	viper.BindEnv("redis.cluster.password", "REDIS_CLUSTER_PASSWORD") //redis集群密码

	viper.BindEnv("snmptask.batchsize", "SNMPTASK_BATCHSIZE")         //snmp采集批次数量
	viper.BindEnv("snmptask.maxGoroutines", "SNMPTASK_MAXGOROUTINES") //snmp goroutines最大数

	viper.BindEnv("leader", "LEADER")
	viper.BindEnv("HeartbeatInterval", "HEARTBEAT_INTERVAL")
	viper.BindEnv("TimeoutThreshold", "TIMEOUT_THRESHOLD")
	viper.BindEnv("ListenPort", "LISTENPORT")
	viper.BindEnv("PeerIP", "PEERIP")
	viper.BindEnv("pids.token", "PIDS_TOKEN") // 绑定PidsToken环境变量

	// 绑定日志配置环境变量
	viper.BindEnv("log.basePath", "LOG_BASE_PATH")
	viper.BindEnv("log.maxsize", "LOG_MAX_SIZE")
	viper.BindEnv("log.maxage", "LOG_MAX_AGE")
	viper.BindEnv("log.maxbackup", "LOG_MAX_BACKUP")
	viper.BindEnv("log.compress", "LOG_COMPRESS")
	viper.BindEnv("log.level", "LOG_LEVEL")

	viper.SetConfigName("application")
	viper.SetConfigType("yaml")
	viper.AddConfigPath("./")

	err := viper.ReadInConfig()
	if err != nil {
		panic(fmt.Sprintf("viper获取配置文件失败: %v", err))
	}

	// 先从环境变量获取并手动设置 DbConfig
	DbConfig = &Database{
		Host:               viper.GetString("datasource.host"),
		Port:               viper.GetString("datasource.port"),
		Username:           viper.GetString("datasource.username"),
		Password:           viper.GetString("datasource.password"),
		Database:           viper.GetString("datasource.database"),
		MaxIdleConnections: viper.GetInt("datasource.maxIdleConns"),
		MaxOpenConnections: viper.GetInt("datasource.maxOpenConns"),
	}

	Rediscfg = &RedisConfig{
		Mode: viper.GetString("redis.mode"),
		Single: SingleConfig{
			Host:     viper.GetString("redis.single.host"),
			Port:     viper.GetString("redis.single.port"),
			Password: viper.GetString("redis.single.password"),
			DB:       viper.GetInt("redis.single.db"),
		},
		Cluster: ClusterConfig{
			Addrs:    viper.GetStringSlice("redis.cluster.addrs"),
			Password: viper.GetString("redis.cluster.password"),
		},
	}
	SnmpTaskCfg = &SnmpTaskConfig{
		BatchSize:     viper.GetInt("snmptask.batchsize"),
		MaxGoroutines: viper.GetInt("snmptask.maxGoroutines"),
	}
	HeartBeatCfg = &HeartBeatConfig{
		Leader:            viper.GetBool("leader"),
		HeartbeatInterval: viper.GetDuration("HeartbeatInterval"),
		TimeoutThreshold:  viper.GetDuration("TimeoutThreshold"),
		ListenPort:        viper.GetString("ListenPort"),
		PeerIP:            viper.GetString("PeerIP"),
	}
	LogCfg = &LogConfig{
		BasePath:  viper.GetString("log.basePath"),
		MaxSize:   viper.GetInt("log.maxsize"),
		MaxAge:    viper.GetInt("log.maxage"),
		MaxBackup: viper.GetInt("log.maxbackup"),
		Compress:  viper.GetBool("log.compress"),
		Level:     viper.GetString("log.level"),
	}

	PidsConfig = &PidsConfiguration{
		PidsToken: viper.GetString("pids.token"),
	}

	if err = viper.UnmarshalKey("log", &LogCfg); err != nil {
		panic(fmt.Sprintf("序列化log配置错误！ %v", err))
	}
}

type LogConfig struct {
	BasePath  string `mapstructure:"basePath"`
	MaxSize   int    `mapstructure:"maxsize"`
	MaxAge    int    `mapstructure:"maxage"`
	MaxBackup int    `mapstructure:"maxbackup"`
	Compress  bool   `mapstructure:"compress"`
	Level     string `mapstructure:"level"` // 新增日志级别配置
}

// Redis 配置结构体
type RedisConfig struct {
	Mode    string        `mapstructure:"mode"`    // "single" 或 "cluster"
	Single  SingleConfig  `mapstructure:"single"`  // 单节点配置
	Cluster ClusterConfig `mapstructure:"cluster"` // 集群配置
}

type SingleConfig struct {
	Host     string `mapstructure:"host"`
	Port     string `mapstructure:"port"`
	Password string `mapstructure:"password"`
	DB       int    `mapstructure:"db"`
}

type ClusterConfig struct {
	Addrs    []string `mapstructure:"addrs"`
	Password string   `mapstructure:"password"`
}

// 心跳检测配置
type HeartBeatConfig struct {
	Leader            bool          // 是否是主节点
	HeartbeatInterval time.Duration // 心跳发送间隔
	TimeoutThreshold  time.Duration // 超时时间
	ListenPort        string        // 监听端口
	PeerIP            string        // 对端节点 IP
}

// Pids 配置结构体
type PidsConfiguration struct {
	PidsToken string `mapstructure:"pidsToken"`
}

// 初始化 Redis 客户端
func InitRedisClient(config *RedisConfig) (redis.UniversalClient, error) {
	switch config.Mode {
	case "single":
		return redis.NewClient(&redis.Options{
			Addr:        config.Single.Host + ":" + config.Single.Port,
			Password:    config.Single.Password,
			DB:          config.Single.DB,
			DialTimeout: 5 * time.Second,
		}), nil
	case "cluster":
		clusterclient := redis.NewClusterClient(&redis.ClusterOptions{
			Addrs:       config.Cluster.Addrs,
			Password:    config.Cluster.Password,
			DialTimeout: 5 * time.Second,
		})
		return clusterclient, nil
	default:
		return nil, fmt.Errorf("unsupported redis mode: %s", config.Mode)
	}
}
